// Copyright (c) 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package reader

type (
	// Reader represents a computation that depends on a shared environment of type R and produces a value of type A.
	//
	// The purpose of the Reader monad is to avoid threading arguments through multiple functions
	// in order to only get them where they are needed. This enables dependency injection and
	// configuration management in a functional style.
	//
	// Type Parameters:
	//   - R: The environment/context type (read-only, shared across computations)
	//   - A: The result type produced by the computation
	//
	// A Reader[R, A] is simply a function from R to A: func(R) A
	//
	// Example:
	//
	//	type Config struct {
	//	    DatabaseURL string
	//	    APIKey      string
	//	}
	//
	//	// A Reader that extracts the database URL from config
	//	getDatabaseURL := func(c Config) string { return c.DatabaseURL }
	//
	//	// A Reader that extracts the API key from config
	//	getAPIKey := func(c Config) string { return c.APIKey }
	//
	//	// Use the readers with a config
	//	config := Config{DatabaseURL: "localhost:5432", APIKey: "secret"}
	//	dbURL := getDatabaseURL(config)  // "localhost:5432"
	//	apiKey := getAPIKey(config)      // "secret"
	Reader[R, A any] = func(R) A

	Kleisli[R, A, B any] = func(A) Reader[R, B]

	// Operator represents a transformation from one Reader to another.
	// It takes a Reader[R, A] and produces a Reader[R, B], where both readers
	// share the same environment type R.
	//
	// This type is commonly used for operations like Map, Chain, and other
	// transformations that convert readers while preserving the environment type.
	//
	// Type Parameters:
	//   - R: The shared environment/context type
	//   - A: The input Reader's result type
	//   - B: The output Reader's result type
	//
	// Example:
	//
	//	type Config struct { Multiplier int }
	//
	//	// An operator that transforms int readers to string readers
	//	intToString := reader.Map[Config, int, string](strconv.Itoa)
	//
	//	getNumber := reader.Asks(func(c Config) int { return c.Multiplier })
	//	getString := intToString(getNumber)
	//	result := getString(Config{Multiplier: 42}) // "42"
	Operator[R, A, B any] = Kleisli[R, Reader[R, A], B]
)
